package cate.game.role.res.guild.po.fairyland;

import cate.common.table.d.GDFunc;
import cate.common.table.d.GDGuild;
import cate.common.table.d.GDOperation;
import cate.common.table.guild.fairyland.base.GuildFairyBaseRow;
import cate.common.table.guild.fairyland.rank.GuildFairyRankRewardRow;
import cate.game.GameBody;
import cate.game.mail.po.MailBuilder;
import cate.game.res.MixRes;
import cate.game.res.MixResAdder;
import cate.game.role.Role;
import cate.game.role.mail.Mail;
import cate.game.role.res.guild.GuildFuncBase;
import cate.game.role.res.guild.po.GuildPO;
import cate.game.role.res.guild.po.fairyland.core.GuildFairyRank;
import cate.game.role.res.guild.po.fairyland.core.GuildFairylandBossPO;
import cate.game.role.res.guild.po.fairyland.core.GuildFairylandState;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.business.game.component.NoticeParam;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.annotation.Transient;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
@NoteClass("公会秘境")
public class GuildFairylandPO extends GuildFuncBase {
    @NoteField("当前开启的BOSS的类型")
    public int openingBossType;
    @NoteField("BOSS开始时间")
    public long bossStartTime;
    @NoteField("BOSS挑战结束时间")
    public long bossChallengeEndTime;
    @NoteField("BOSS冷却结束时间")
    public long bossColdEndTime;
    @NoteField("BOSS数据")
    public Map<Integer, GuildFairylandBossPO> bossPOMap;

    @Transient
    @JsonIgnore
    private GameBody game;
    @Transient
    @JsonIgnore
    private ReentrantLock lock;

    @Override
    public void initialize(GuildPO parent) {
        super.initialize(parent);
        game = parent.game;
        if (bossPOMap == null) {
            bossPOMap = new HashMap<>();
        }
        excelCheck();
        bossPOMap.values().forEach(po -> po.initialize(funcDependent.guild));
        if (lock == null) {
            lock = new ReentrantLock();
        }
    }

    /**
     * Excel配置检测
     */
    private void excelCheck() {
        bossPOMap.entrySet().removeIf(e -> !game.table.guildFairyland.base.bossMaxIndex.containsKey(e.getKey()));
        game.table.guildFairyland.base.bossMaxIndex.keySet().forEach(bossId -> {
            if (!bossPOMap.containsKey(bossId)) {
                bossPOMap.put(bossId, new GuildFairylandBossPO(game, bossId));
            }
        });
    }

    @Override
    public int getFuncId() {
        return GDFunc.GuildFunc.FAIRYLAND;
    }

    /**
     * 通知所有成员
     */
    public void noticeAllMembers() {
        funcDependent.guild.member.getOnlineRole().forEach(role -> {
            role.getFarm().guildFairyland.checkState();
            role.getFarm().guildFairyland.noticeUpdate();
        });
    }

    /**
     * 挑战状态清空
     */
    public void clearChallenge() {
        openingBossType = 0;
        bossStartTime = 0;
        bossChallengeEndTime = 0;
    }

    /**
     * 循环
     */
    public void tick() {
        long nowTime = System.currentTimeMillis();
        if (openingBossType == 0) {
            if (bossColdEndTime != 0 && bossColdEndTime <= nowTime) {
                bossColdEndTime = 0;
                noticeAllMembers();
            }
            return;
        }
        GuildFairylandBossPO bossPO = bossPOMap.get(openingBossType);
        if (bossPO == null) {
            clearChallenge();
            noticeAllMembers();
            return;
        }
        GuildFairyBaseRow baseRow = bossPO.getBaseRow();
        if (baseRow == null) {
            clearChallenge();
            noticeAllMembers();
            return;
        }
        if (bossPO.state == GuildFairylandState.CHALLENGE) {
            if (nowTime > bossChallengeEndTime) {
                bossPO.state = GuildFairylandState.CLOSE;
                // 结算
                for (int i = 0; i < bossPO.rankList.size(); i++) {
                    int rank = i + 1;
                    GuildFairyRank rankPO = bossPO.rankList.get(i);
                    GuildFairyRankRewardRow rankRewardRow = game.table.guildFairyland.rank_reward.getRowByRank(baseRow.id, rank);
                    if (rankRewardRow == null) {
                        continue;
                    }
                    Mail mail = new MailBuilder().setContentId(GDGuild.Fairyland.RANK_MAIL_ID)
                            .setNoticeParamList(new NoticeParam(NoticeParam.NoticeType.STRING, String.valueOf(rank)))
                            .setReward(new MixRes(rankRewardRow.rewardStr))
                            .setOperation(GDOperation.GUILD_FAIRYLAND_RANK)
                            .setOperationSub(rank)
                            .build();
                    game.mail.send(rankPO.owner.uid, mail);
                }
                clearChallenge();
                noticeAllMembers();
            }
        }
    }

    /**
     * 开启秘境BOSS
     *
     * @param bossType BOSS类型
     * @return 开启结果
     */
    public EcResult<Void> startBoss(int bossType) {
        lock.lock();
        try {
            EcResult<Void> r = new EcResult<>();
            if (openingBossType != 0) {
                return r.fail("公会秘境已开启");
            }
            long nowTime = System.currentTimeMillis();
            if (nowTime < bossColdEndTime) {
                return r.fail("公会秘境开启冷却中");
            }
            if (!bossPOMap.containsKey(bossType)) {
                return r.fail("未知的BOSS类型");
            }
            r = bossPOMap.get(bossType).open();
            if (!r.ok()) {
                return r;
            }
            openingBossType = bossType;
            bossStartTime = nowTime;
            bossChallengeEndTime = bossStartTime + GDGuild.Fairyland.CHALLENGE_TIME;
            bossColdEndTime = bossStartTime + GDGuild.Fairyland.COLD_TIME;
            noticeAllMembers();
            return r.success();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 尝试发起挑战
     *
     * @param role 玩家
     * @return 挑战结果
     */
    public EcResult<Void> tryChallenge(Role role) {
        EcResult<Void> r = new EcResult<>();
        GuildFairylandBossPO bossPO = bossPOMap.get(openingBossType);
        if (bossPO == null) {
            return r.fail("公会秘境没有开启");
        }
        lock.lock();
        EcResult<Boolean> r_c;
        try {
            r_c = bossPO.challenge(role);
            if (!r_c.ok()) {
                return r.fail(r_c.code, r_c.message);
            }
        } finally {
            lock.unlock();
        }
        if (r_c.data) {
            // 追击直接发追击奖励
            GuildFairyBaseRow baseRow = bossPO.getBaseRow();
            if (baseRow != null) {
                new MixResAdder().setRes(baseRow.followReward)
                        .setSendMailWhenFull(true)
                        .setDialogReward(true)
                        .setOperation(GDOperation.GUILD_FAIRYLAND_FOLLOW)
                        .setOperationSub(baseRow.id)
                        .exe(role);
            }
        }
        return r.success();
    }
}
